Module Architecture
flowchart TD
BASE["sadeem_saas_base\nSAAS Base"]
NPM["sadeem_nginx_proxy_manager\nNginx Proxy Manager"]
CF["sadeem_cloudflare\nCloudflare"]
S["sadeem.subscription\ndomain · DNS · Nginx · DB\nbilling · Git · notifications"]
ST["sadeem.subscription.stage\ndev / test / prod instances"]
PKG["sadeem.subscription.package\nOdoo module collections"]
MOD["sadeem.subscription.module\nOdoo module reference"]
TPL["sadeem.subscription.db.template\npre-built DB snapshots"]
BKL["sadeem.subscription.backup.line\nbackup file records"]
COL["sadeem.subscription.collaborator\nteam access + portal invite"]
UPD["sadeem.subscription.update.request\nresource upgrade requests"]
LIM["sadeem.subscription.model.limit\nper-model record limits"]
BASE --> S
NPM --> S
CF --> S
S --> ST
S --> PKG
PKG --> MOD
PKG --> TPL
S --> BKL
S --> COL
S --> UPD
S --> LIM
S --> A1([action_confirm\nvalidate + start provisioning])
S --> A2([action_run_subscription\nbuild DNS · Nginx · DB])
S --> A3([action_stop\npause + redirect traffic])
S --> A4([action_start\nresume stopped subscription])
S --> A5([action_cancel\ndelete all resources])
S --> A6([action_get_subscription_info\nGET slave database info])
S --> A7([action_execute_sql\nrun SQL on slave DB])
S --> A8([subscription_diagnosis_fix\nfix DNS · Nginx · DB issues])
S --> A9([action_sync_model_limits\npush limits to slave])
S --> A10([action_enable_mobile_notifications\nntfy / FCM token setup])
S --> A11([action_create_portal_user\ncreate portal user on slave])
S --> A12([action_create_backup_record\nregister with backup server])
S --> A13([action_get_backup_line\nsync backup list])
S --> A14([action_create_code_server\ndeploy VS Code container])
S --> A15([action_install_subscription_modules\ninstall modules on slave DB])
Module Description
Core SaaS subscription lifecycle management. Handles subscription provisioning (DNS, Nginx, database), billing via sale orders and invoices, multi-stage environments, collaborator access with portal invites, backup management, resource upgrade requests, model limits, Git integration, push notifications, SQL console, and customer self-service portal.
Dependencies
base,web,mail,sale,account,portalsadeem_saas_basesadeem_nginx_proxy_managersadeem_cloudflare
Menus
SAAS Management
├─ Dashboard
⎢ └─ Subscription Dashboard
├─ Subscriptions
⎢ ├─ Subscriptions
⎢ ├─ Stages
⎢ └─ Update Requests
├─ Data
⎢ ├─ Packages
⎢ ⎢ ├─ Subscription Packages
⎢ ⎢ └─ Subscription Modules
⎢ ├─ Database Templates
⎢ └─ Reserved Domains
└─ Configuration
└─ Settings
Subscription Lifecycle
The subscription follows a defined state flow from creation to deployment
Draft → Confirm → Build → Run
↓
Build Failed
Run → Stop → Start (Run)
↓
Terminate / Cancel
| State | Description |
|---|---|
| Draft | Initial creation, all fields editable |
| Confirmed | Validated, ready for deployment |
| Building | Infrastructure provisioning in progress (DNS, Nginx, Database) |
| Build Failed | Deployment encountered an error |
| Running | Live and accepting traffic |
| Stopped | Paused, can be resumed. Traffic redirected |
| Terminated | Permanently disabled |
| Cancelled | All resources deleted and cleaned up |
Key Fields
Subscription (sadeem.subscription)
| Field | Type | Description |
|---|---|---|
| partner_id | Many2one | Customer/client (required) |
| state | Selection | Lifecycle state: draft, confirm, build, build_fail, run, stop, terminate, cancel |
| saas_subscription_type | Selection | Deployment strategy (docker or dbfilter — added by deployment modules) |
| domain | Char | Primary domain for the subscription |
| start_date / end_date | Date | Subscription period |
| user_limit | Integer | Maximum number of users allowed (required) |
| subscription_package | Many2many | Associated Odoo module packages |
| stage_ids | One2many | Dev/test/staging environments linked to this subscription |
| stage_limit | Integer | Max number of stages allowed |
| storage_limit | Integer | Storage quota in MB |
| storage_used | Float | Computed total storage used (DB + filestore + addons) |
| http_port | Integer | Port the main Odoo instance listens on (set at provisioning) |
| server_ip | Char | IP of the server running this subscription |
| root_server | Many2one | Root server for SSH operations |
| backup_server_id | Many2one | Remote backup server |
| backup_uuid | Char | UUID assigned by the backup server |
| backup_state | Selection | not_configured, active, inactive, error |
| keep_latest_backup | Integer | Number of backups to retain (default: 7) |
| daily/weekly/monthly_backup_count | Integer | Backup frequency settings |
| nginx_server | Many2one | NPM connector for this subscription |
| nginx_host | Many2one | NPM proxy host record |
| nginx_proxy_create_record | Boolean | Auto-create Nginx proxy host on provisioning |
| cloudflare_connector_id | Many2one | Cloudflare account for DNS management |
| cloudflare_record | Many2one | Cloudflare DNS record for this subscription |
| cloudflare_create_record | Boolean | Auto-create DNS record on provisioning |
| cloudflare_proxied_record | Boolean | Whether DNS record is proxied through Cloudflare |
| build_step_dns | Boolean | Whether the DNS provisioning step completed |
| build_step_nginx | Boolean | Whether the Nginx provisioning step completed |
| build_step_instance | Boolean | Whether the DB/instance provisioning step completed |
| build_fail_message | Text | Error message when build fails |
| git_integration | Boolean | Whether Git code sync is enabled |
| saas_repository_id | Many2one | Linked Git repository |
| git_branch_name | Char | Git branch to sync |
| ntfy_server_id | Many2one | Push notification server |
| mobile_notifications_enabled | Boolean | Whether mobile push notifications are active |
| ntfy_token | Char | Per-subscription ntfy token |
| ntfy_token_status | Selection | active, expired, not_set |
| control_model_limit | Boolean | Whether per-model record limits are enforced |
| control_model_limit_line | One2many | Per-model limit rules |
| collaborator_line | One2many | Collaborators with access and portal state |
| uuid | Char | Unique identifier (auto-generated) |
| protected_subscription | Boolean | Prevents accidental deletion |
| grace_period | Integer | Days after end date before auto-stopping |
| redirect_ended_to | Char | URL to redirect traffic to when subscription ends |
| saas_slave_enabled | Boolean | Whether SAAS slave API is enabled |
| database_template | Many2one | Pre-built DB template to restore on provisioning |
Subscription Stage (sadeem.subscription.stage)
| Field | Type | Description |
|---|---|---|
| subscription_id | Many2one | Parent subscription (required) |
| domain | Char | Domain for this stage (required) |
| state | Selection | Stage lifecycle: build, run, stop, terminate, cancel |
| http_port | Integer | Port this stage's Odoo listens on |
| empty_database | Boolean | Create an empty database (no template) |
| demo_data | Boolean | Include Odoo demo data |
| git_branch_name | Char | Branch override for this stage |
| cloudflare_record | Many2one | DNS record for this stage |
| nginx_host | Many2one | Nginx proxy host for this stage |
| database_size / filestore_size / user_addons_size | Float | Storage usage breakdown in MB |
| active_user_count | Integer | Number of active users on this stage |
| stop_by_cron | Boolean | Whether this stage was stopped by a scheduled cron |
Subscription Package (sadeem.subscription.package)
| Field | Type | Description |
|---|---|---|
| module_ids | Many2many | Odoo modules included in this package |
| db_template_id | Many2one | Default database template for this package |
Collaborator (sadeem.subscription.collaborator)
| Field | Type | Description |
|---|---|---|
| subscription_id | Many2one | Parent subscription |
| user_id / partner_id | Many2one | Collaborator identity |
| portal_state | Selection | invited, active, inactive |
Model Limit (sadeem.subscription.model.limit)
| Field | Type | Description |
|---|---|---|
| subscription_id | Many2one | Parent subscription |
| model_name | Char | Technical Odoo model name to limit |
| limit | Integer | Maximum number of records allowed |
Key Actions
| Action | Model | Description |
|---|---|---|
action_confirm |
sadeem.subscription | Validates domain, sets main domain/subdomain defaults, moves to confirm; triggers provisioning via action_run_subscription |
action_run_subscription |
sadeem.subscription | Provisions DNS (Cloudflare), Nginx proxy, and the Odoo instance (Docker/DBFilter specific) |
action_reset_draft |
sadeem.subscription | Resets subscription to draft state |
action_stop |
sadeem.subscription | Pauses running subscription; stops Nginx host, redirects traffic |
action_start |
sadeem.subscription | Resumes stopped subscription; re-enables Nginx host |
action_cancel |
sadeem.subscription | Deletes all provisioned resources (DNS, Nginx, DB); moves to cancel |
action_create_stage |
sadeem.subscription | Creates a new dev/test stage environment |
action_get_subscription_info |
sadeem.subscription | Fetches live database/user info from the slave Odoo instance |
action_execute_sql |
sadeem.subscription | Runs SQL from sql_input on the slave database |
subscription_diagnosis_fix |
sadeem.subscription | Detects and repairs broken DNS / Nginx / DB configuration |
action_sync_model_limits |
sadeem.subscription | Pushes control_model_limit_line rules to the slave instance |
action_enable_mobile_notifications |
sadeem.subscription | Sets up ntfy/FCM token for push notifications |
action_create_backup_record |
sadeem.subscription | Registers subscription with the remote backup server |
action_get_backup_line |
sadeem.subscription | Syncs backup file list from remote backup server |
action_create_code_server |
sadeem.subscription | Deploys VS Code server container for this subscription |
action_install_subscription_modules |
sadeem.subscription | Installs Odoo modules from the subscription's packages |
action_create_portal_user |
sadeem.subscription | Creates a portal user account on the slave database |
action_link_git_webhook |
sadeem.subscription | Registers a GitHub webhook for the linked repository |
action_redirect_host_to_ended_link |
sadeem.subscription | Redirects Nginx host to redirect_ended_to URL |
Warnings & Important Notes
- Deletion blocked: Cannot delete a subscription not in
draftorcancelstate — raisesValidationError. - Protected subscriptions: Setting
protected_subscription = Trueraises an error if deletion is attempted. - Domain validation:
action_confirmraisesUserErrorif no main domain is defined,ValidationErrorif the domain is already in use or fails format validation. - Root server required:
action_confirmraisesValidationErrorif no root server is set when git integration is enabled. - Destination addons dir required: Raises
ValidationErrorifdestination_addons_diris empty when git is enabled. - ntfy constraints:
action_enable_mobile_notificationsraisesValidationErrorif no ntfy server is configured orauto_generate_tokensis not enabled. - Nginx host creation failure:
action_run_subscriptionraisesValidationErrorif Nginx host creation or start fails. - Cloudflare record failure:
action_run_subscriptionraisesValidationErrorif DNS record creation fails. - SQL constraint on UUID:
_sql_constraintsenforcesUNIQUE(uuid)onsadeem.subscription. - Build step tracking:
build_step_dns,build_step_nginx,build_step_instancetrack which provisioning steps completed; used bysubscription_diagnosis_fixto determine what needs repair. - Secret key required: Encryption operations raise
UserErrorif thesadeem_saas_secret_keysystem parameter is missing (set by post-install hook insadeem_saas_base). - Grace period: Subscriptions with an
end_dateare not stopped immediately;grace_periodadds extra days before the scheduled cron stops them. - Stage state starts at
build: Unlike subscriptions which start atdraft, stages default to statebuild.